package com.lsp.concurrent.locks;

import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;

@Slf4j
public class LSPReentrantLock implements  Serializable {

    private final Sync sync;

    public LSPReentrantLock() {
        sync = new NonfairSync();
    }

    abstract static class Sync extends LSPAbstractQueuedSynchronizer{

        abstract void lock();
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if(c == 0){
                log.info("第二次尝试抢占到锁的线程是"+Thread.currentThread().getName());
                if(compareAndSetState(0,acquires)){
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if(current == getExclusiveOwnerThread()){
                int nextc = c + acquires;
                if(c < 0)
                    throw new Error("Maximum lock count exceeded");
                    setState(nextc);
                    return true;
            }
            return false;
        }

        protected final boolean tryRelease(int releases){
            int c = getState() - releases;
            if(Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if(c == 0){
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

        protected final boolean isHeldExclusively() {
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        final LSPConditionObject newCondition() {
            return new LSPConditionObject();
        }
    }


    static final class NonfairSync extends Sync {
        final void lock() {
            if(compareAndSetState(0,1)){
                log.info("第一次尝试抢占到锁的线程是"+Thread.currentThread().getName());
                setExclusiveOwnerThread(Thread.currentThread());}
            else{
                log.info("第一次尝试获取锁失败的线程是"+Thread.currentThread().getName());
                acquire(1);
            }
        }
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }


    }

    static final class FairSync extends Sync {
        void lock() {
        }
    }

    public void lock() {
        sync.lock();
    }

    public void unlock() {
        sync.release(1);
    }

    public LSPCondition newCondition() {
        return sync.newCondition();
    }
}
